<?php
/*
	FusionPBX
	Version: MPL 1.1

	The contents of this file are subject to the Mozilla Public License Version
	1.1 (the "License"); you may not use this file except in compliance with
	the License. You may obtain a copy of the License at
	http://www.mozilla.org/MPL/

	Software distributed under the License is distributed on an "AS IS" basis,
	WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
	for the specific language governing rights and limitations under the
	License.

	The Original Code is FusionPBX

	The Initial Developer of the Original Code is
	Mark J Crane <markjcrane@fusionpbx.com>
	Portions created by the Initial Developer are Copyright (C) 2008-2025
	the Initial Developer. All Rights Reserved.

	Contributor(s):
	Mark J Crane <markjcrane@fusionpbx.com>
*/

//includes files
	require_once __DIR__ . "/require.php";

//add multi-lingual support
	$language = new text;
	$text = $language->get(null,'core/user_settings');

//connect to the database
	$database = database::new();

//set the current domain_uuid
	$domain_uuid = $_SESSION['domain_uuid'] ?? '';

//initialize the settigns object
	$settings = new settings(['database' => $database, 'domain_uuid' => $domain_uuid]);

//get action, if any - define, request, reset
	if (isset($_REQUEST['action'])) {
		$action = $_REQUEST['action'];
	}

//get the domains if user has permission for show all
	$domains = [];
	if ($has_device_domain_all) {
		$rows = $database->select("select domain_uuid, domain_name from v_domains");
		if (!empty($rows)) {
			foreach ($rows as $row) {
				$domains[$row['domain_uuid']] = $row['domain_name'];
			}
		}
	}

//send an email with the password reset link
	if (isset($action) && $action == 'request' && isset($_REQUEST['email'])) {
		if (valid_email($_REQUEST['email'])) {
			//set the email address
				$email = $_REQUEST['email'];

			//see if email exists
				$sql = "select ";
				$sql .= "user_uuid, ";
				$sql .= "username, ";
				$sql .= "password, ";
				$sql .= "domain_uuid ";
				$sql .= "from v_users ";
				$sql .= "where user_email = :email ";
				$parameters['email'] = $email;
				$results = $database->select($sql, $parameters, 'all');
				unset($sql, $parameters);

			//check for duplicates
				if (is_array($results) && @sizeof($results) != 0) {

					if (@sizeof($results) == 1) {
						$result = $results[0];

						if ($result['username'] != '') {
							//set valid email
								$_SESSION['valid_email'] = $email;

							//set the password reset domain
								$password_reset_domain = $_SESSION['domain_name'];

							//generate reset link email and body variables
								$domain_uuid = $result['domain_uuid'];
								if ($settings->get('login', 'password_reset_domain', '') != '') {
									$password_reset_domain = $settings->get('login', 'password_reset_domain', '');
								}
								else {
									foreach ($domains as $domain) {
										if (strtolower($domain) == strtolower($_SERVER['HTTP_HOST'])) {
											$password_reset_domain = $_SERVER['HTTP_HOST'];
											break;
										}
									}
								}
								$key = encrypt($settings->get('login', 'password_reset_key', ''), $result['username'].'|'.$result['domain_uuid'].'|'.$result['password']);
								$reset_link = "https://".$password_reset_domain.PROJECT_PATH."/resources/login.php?action=define&key=".urlencode($key);
								$reset_button = email_button(strtoupper($text['label-reset_password']), $reset_link, ($_SESSION['theme']['button_background_color_email']['text'] ? $_SESSION['theme']['button_background_color_email']['text'] : '#2e82d0'), ($_SESSION['theme']['button_text_color_email']['text'] ? $_SESSION['theme']['button_text_color_email']['text'] : '#ffffff'));
								$logo_full = '';
								$logo_shield = '';

							//get user language code, if exists
								$sql = "select user_setting_value from v_user_settings ";
								$sql .= "where user_uuid = :user_uuid ";
								$sql .= "and domain_uuid = :domain_uuid ";
								$sql .= "and user_setting_category = 'domain' ";
								$sql .= "and user_setting_subcategory = 'language' ";
								$sql .= "and user_setting_name = 'code' ";
								$parameters['user_uuid'] = $result['user_uuid'];
								$parameters['domain_uuid'] = $domain_uuid;
								$row = $database->select($sql, $parameters, 'row');
								if (is_array($row) && @sizeof($row) != 0) {
									$user_language_code = $row['user_setting_value'];
								}
								unset($sql, $parameters, $row);

							//get the email template from database
								$sql = "select template_subject, template_body from v_email_templates ";
								$sql .= "where template_language = :template_language ";
								$sql .= "and (domain_uuid = :domain_uuid or domain_uuid is null) ";
								$sql .= "and template_category = 'password_reset' ";
								$sql .= "and template_subcategory = 'default' ";
								$sql .= "and template_type = 'html' ";
								$sql .= "and template_enabled = true ";
								$parameters['template_language'] = $user_language_code ? $user_language_code : $settings->get('domain', 'language', 'en-us');
								$parameters['domain_uuid'] = $domain_uuid;
								$row = $database->select($sql, $parameters, 'row');
								if (is_array($row)) {
									$email_subject = $row['template_subject'];
									$email_body = $row['template_body'];
								}
								unset($sql, $parameters, $row);

							//replace variables in email body
								$email_body = str_replace('${reset_link}', $reset_link, $email_body);
								$email_body = str_replace('${reset_button}', $reset_button, $email_body);
								$email_body = str_replace('${logo_full}', $logo_full, $email_body);
								$email_body = str_replace('${logo_shield}', $logo_shield, $email_body);
								$email_body = str_replace('${domain}', $domain_name, $email_body);

							//send reset link
								if (send_email($email, $email_subject, $email_body, $eml_error)) {
									//email sent
									message::add($text['message-reset_link_sent'], 'positive', 2500);
								}
								else {
									//email failed
									//message::add($eml_error, 'negative', 5000);
								}
						}
						else {
							//not found
							message::add($text['message-reset_link_sent'], 'negative', 5000);
						}

					}
					else {
						//matched multiple users
						message::add($text['message-reset_link_sent'], 'negative', 5000);
					}

				}
				else {
					//not found
					message::add($text['message-reset_link_sent'], 'negative', 5000);
				}

		}
		//else {
		//	//invalid email
		//	message::add($text['message-invalid_email'], 'negative', 5000);
		//}
	}

//validate the password reset key
	if (isset($action) && $action == 'define') {
		//get the key and decrypt and parse it
			$key = $_GET['key'];
			$key_part = explode('|', decrypt($settings->get('login', 'password_reset_key', ''), $key));
			$username = $key_part[0];
			$domain_uuid = $key_part[1];
			$password_submitted = $key_part[2];

		//get the user_email
			$user_email = $_SESSION['valid_email'];

		//get current, see if same as submitted salt
			$sql = "select username, password from v_users ";  //user_token_hash, user_token_expires
			$sql .= "where domain_uuid = :domain_uuid ";
			$sql .= "and username = :username ";
			//$sql .= "and user_email = :user_email ";
			$parameters['domain_uuid'] = $domain_uuid;
			$parameters['username'] = $username;
			//$parameters['user_email'] = $user_email;
			$row = $database->select($sql, $parameters, 'row');
			$password_current = $row['password'];
			unset($sql, $parameters);

		//the key has been validated set the reset flag
			if ($username != '' && $password_submitted == $password_current) {
				$_SESSION['valid_username'] = $row['username'];
				$_SESSION['valid_domain'] = $domain_uuid;
				$_SESSION['valid_reset'] = true;
			}
			else {
				header("Location: /login.php");
				exit;
			}
	}

//reset the password
	if ($_SESSION['valid_reset'] && !empty($_SESSION['valid_username']) && !empty($_REQUEST['password_new'])  && !empty($_REQUEST['password_repeat'])) {
		//$username = trim($_REQUEST['username']);
		$password_new = trim($_REQUEST['password_new']);
		$password_repeat = trim($_REQUEST['password_repeat']);

		//if not requiring usernames to be of email format, strip off @domain as the valid domain for the reset is already being provided in the where clause below
		//if ($settings->get('users', 'username_format', '') != 'email') {
		//	$username = substr_count($username, '@') != 0 ? explode('@', $username)[0] : $username;
		//}

		if ($password_new === $password_repeat && check_password_strength($password_new, $text, 'user')) {

			//set the password hash cost
			$options = array('cost' => 10);

			//update the pasword
			$sql  = "update v_users set ";
			$sql .= "password = :password, ";
			$sql .= "salt = null ";
			$sql .= "where domain_uuid = :domain_uuid ";
			$sql .= "and username = :username ";
			$parameters['domain_uuid'] = $_SESSION['valid_domain'];
			$parameters['password'] = password_hash($password_new, PASSWORD_DEFAULT, $options);
			$parameters['username'] = $_SESSION['valid_username'];
			$database->execute($sql, $parameters);
			unset($sql, $parameters);

			//set the message to password reset completed
			message::add($text['message-password_reset'], 'positive', 2500);

			//unset the php session
			unset($_SESSION);

			//redirect the browser
			header('Location: //'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
			exit;

		}
	}

//get the http values and set as variables
	$msg = isset($_GET["msg"]) ? $_GET["msg"] : null;

//set variable if not set
	$login_domain_name_visible = $settings->get('login', 'domain_name_visible', false);

//santize the login destination url and set a default value
	if (!empty($settings->get('login', 'destination', ''))) {
		$destination_path = parse_url($settings->get('login', 'destination', ''))['path'] ?? '';
		$destination_query = parse_url($settings->get('login', 'destination', ''))['query'] ?? '';
		$destination_path = preg_replace('#[^a-zA-Z0-9_\-\./]#', '', $destination_path);
		$destination_query = preg_replace('#[^a-zA-Z0-9_\-\./&=]#', '', $destination_query);
		$login_destination = (!empty($destination_query)) ? $destination_path.'?'.$destination_query : $destination_path;
	}
	else {
		$login_destination = PROJECT_PATH."/core/dashboard/";
	}

//set the redirect path
	if (!empty($_REQUEST['path'])) {
		$_SESSION['redirect_path'] = $_REQUEST['path'];
	}

//get the user settings
	$user_setting['length'] = $settings->get('users', 'password_length', '10');
	$user_setting['number'] = $settings->get('users', 'password_number', true);
	$user_setting['lowercase'] = $settings->get('users', 'password_lowercase', true);
	$user_setting['uppercase'] = $settings->get('users', 'password_uppercase', false);
	$user_setting['special'] = $settings->get('users', 'password_special', false);

//add the header
	$document['title'] = $text['title-login'];
	include "resources/header.php";

//show the content
	echo "<script>";
	echo "	var speed = 350;";
	echo "	function toggle_password_reset(hide_id, show_id, focus_id) {";
	echo "		if (focus_id == undefined) { focus_id = ''; }";
	echo "		$('#'+hide_id).slideToggle(speed, function() {";
	echo "			$('#'+show_id).slideToggle(speed, function() {";
	echo "				if (focus_id != '') {";
	echo "					$('#'+focus_id).trigger('focus');";
	echo "				}";
	echo "			});";
	echo "		});";
	echo "	}";
	echo "</script>";

//send an email with the password reset link
	if (isset($action) && $action == 'request' && !empty($_SESSION['valid_email'])) {
		echo "<div class='card' style='text-align: center;'>\n";
		echo "	<h5>".$text['label-email_sent']."</h5>\n";
		echo "	".$text['description-email_sent']."<br />\n";
		echo "</div>\n";
	}

//request the email address
	if (empty($_SESSION['valid_email']) && !isset($_SESSION['valid_reset'])) {

		//create token
		$object = new token;
		$token = $object->create('login');

		echo "<div id='request_form' class='card'>\n";
		echo "	<div style='text-align: center;'>\n";
		echo "		<h5>".$text['label-forgot_password']."</h5>\n";
		echo "		".$text['description-forgot_password']."\n";
		echo "		<br /><br />\n";
		echo "		<form name='request' method='post'>\n";
		echo "			<input type='hidden' name='action' value='request'>\n";
		echo "			<input type='text' class='txt login' style='text-align: center; min-width: 200px; width: 200px; margin-bottom: 8px;' name='email' id='email' placeholder=\"".$text['label-email_address']."\"><br />\n";
		echo "			<input type='submit' id='btn_reset' class='btn' style='width: 100px; margin-top: 15px;' value='".$text['button-send']."'>\n";
		echo "		</form>";
		echo "	</div>\n";
		echo "</div>";

	}

//request the new_password and the repeat_password
	if (isset($_SESSION['valid_reset']) && $_SESSION['valid_reset']) {

		echo "<script>\n";
		echo "	function compare_passwords() {\n";
		echo "		if (document.getElementById('password') === document.activeElement || document.getElementById('password_confirm') === document.activeElement) {\n";
		echo "			if ($('#password').val() != '' || $('#password_confirm').val() != '') {\n";
		echo "				if ($('#password').val() != $('#password_confirm').val()) {\n";
		echo "					$('#password').removeClass('formfld_highlight_good');\n";
		echo "					$('#password_confirm').removeClass('formfld_highlight_good');\n";
		echo "					$('#password').addClass('formfld_highlight_bad');\n";
		echo "					$('#password_confirm').addClass('formfld_highlight_bad');\n";
		echo "				}\n";
		echo "				else {\n";
		echo "					$('#password').removeClass('formfld_highlight_bad');\n";
		echo "					$('#password_confirm').removeClass('formfld_highlight_bad');\n";
		echo "					$('#password').addClass('formfld_highlight_good');\n";
		echo "					$('#password_confirm').addClass('formfld_highlight_good');\n";
		echo "				}\n";
		echo "			}\n";
		echo "		}\n";
		echo "		else {\n";
		echo "			$('#password').removeClass('formfld_highlight_bad');\n";
		echo "			$('#password_confirm').removeClass('formfld_highlight_bad');\n";
		echo "			$('#password').removeClass('formfld_highlight_good');\n";
		echo "			$('#password_confirm').removeClass('formfld_highlight_good');\n";
		echo "		}\n";
		echo "	}\n";

		echo "	function check_password_strength(pwd) {\n";
		echo "			return true;\n";
		echo "		if ($('#password').val() != '' || $('#password_confirm').val() != '') {\n";
		echo "			var msg_errors = [];\n";
		if (is_numeric($user_setting['length']) && $user_setting['length'] != 0) {
			echo "		var re = /.{".$user_setting['length'].",}/;\n"; //length
			echo "		if (!re.test(pwd)) { msg_errors.push('".$user_setting['length']."+ ".$text['label-characters']."'); }\n";
		}
		if ($user_setting['number']) {
			echo "		var re = /(?=.*[\d])/;\n";  //number
			echo "		if (!re.test(pwd)) { msg_errors.push('1+ ".$text['label-numbers']."'); }\n";
		}
		if ($user_setting['lowercase']) {
			echo "		var re = /(?=.*[a-z])/;\n";  //lowercase
			echo "		if (!re.test(pwd)) { msg_errors.push('1+ ".$text['label-lowercase_letters']."'); }\n";
		}
		if ($user_setting['uppercase']) {
			echo "		var re = /(?=.*[A-Z])/;\n";  //uppercase
			echo "		if (!re.test(pwd)) { msg_errors.push('1+ ".$text['label-uppercase_letters']."'); }\n";
		}
		if ($user_setting['special']) {
			echo "		var re = /(?=.*[\W])/;\n";  //special
			echo "		if (!re.test(pwd)) { msg_errors.push('1+ ".$text['label-special_characters']."'); }\n";
		}
		echo "			if (msg_errors.length > 0) {\n";
		echo "				var msg = '".$text['message-password_requirements'].": ' + msg_errors.join(', ');\n";
		echo "				display_message(msg, 'negative', '6000');\n";
		echo "				return false;\n";
		echo "			}\n";
		echo "			else {\n";
		echo "				return true;\n";
		echo "			}\n";
		echo "		}\n";
		echo "		else {\n";
		echo "			return true;\n";
		echo "		}\n";
		echo "	}\n";

		echo "	function show_strength_meter() {\n";
		echo "		$('#pwstrength_progress').slideDown();\n";
		echo "	}\n";
		echo "</script>\n";

		echo "<div id='reset_form' class='card'>\n";
		echo "	<div style='text-align: center;'>\n";
		echo "		<h5>".$text['label-password_reset']."</h5>\n";
		echo "		<form name='reset' id='frm' method='post'>\n";
		echo "			<input type='hidden' name='action' value='reset'>\n";
		//echo "			<input type='password' style='display: none;' id='password' name='password_auto' value='password'>\n";
		//echo "			<input type='text' class='txt login' style='text-align: center; min-width: 200px; width: 200px; margin-bottom: 8px;' name='username' id='username' placeholder=\"".$text['label-username']."\"><br />\n";
		echo "			<input type='password' class='txt login' style='text-align: center; min-width: 200px; width: 200px; margin-bottom: 4px;' name='password_new' id='password' autocomplete='off' placeholder=\"".$text['label-new_password']."\" onkeypress='show_strength_meter();' onfocus='compare_passwords();' onkeyup='compare_passwords();' onblur='compare_passwords();'><br />\n";
		echo "			<div id='pwstrength_progress' class='pwstrength_progress pwstrength_progress_password_reset'></div>";
		echo "			<input type='password' class='txt login' style='text-align: center; min-width: 200px; width: 200px; margin-top: 4px; margin-bottom: 8px;' name='password_repeat' id='password_confirm' autocomplete='off' placeholder=\"".$text['label-repeat_password']."\" onfocus='compare_passwords();' onkeyup='compare_passwords();' onblur='compare_passwords();'><br />\n";
		echo "			<input type='button' class='btn' style='width: 100px; margin-top: 15px;' value='".$text['button-save']."' onclick=\"if (check_password_strength(document.getElementById('password').value)) { submit_form(); }\">\n";
		//echo "			<input type='button' class='btn' style='width: 100px; margin-top: 15px;' value='".$text['button-save']."' onclick=\"submit_form();\">\n";
		//echo "		<br><br><a class='login_link' onclick=\"document.location.href='login.php';\">".$text['label-cancel']."</a>";
		echo "		</form>";
		echo "	</div>\n";

		echo "	<script>\n";
		//echo "		$('#password').trigger('focus');\n";
		// convert password fields to text
		echo "		function submit_form() {\n";
		echo "			hide_password_fields();\n";
		echo "			$('form#frm').submit();\n";
		echo "		}\n";
		echo "	</script>\n";
		echo "</div>";

	}

//add the footer
	$login_page = true;
	include "resources/footer.php";

?>
